package com.lastproject.ejb.dao;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Date;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.xml.bind.DatatypeConverter;

import com.lastproject.dto.ConfidentialEmployeeDTO;
import com.lastproject.ejb.entities.ConfidentialEmployee;
import com.lastproject.ejb.entities.Department;
import com.lastproject.ejb.entities.Employee;
import com.lastproject.ejb.entities.Role;
import com.lastproject.ejb.entities.User;
import com.lastproject.ejb.service.MailSender;
import com.lastproject.ejb.service.PasswordEncryption;
import com.lastproject.ejb.util.ConfidentialEmployeeConversion;

/**
 * Session Bean implementation class ConfidentialEmployeeDAO
 */
@Stateless
public class ConfidentialEmployeeDAO implements ConfidentialEmployeeDAORemote {

	@PersistenceContext
	EntityManager entityManager;

	@EJB
	ConfidentialEmployeeConversion conv;

	public ConfidentialEmployeeDAO() {

	}

	@Override
	public void create(ConfidentialEmployeeDTO ceDTO) {
		System.out.println("In dao create method");

		// initial password, represented as a string
		String tempPass = ceDTO.getPassword();
		String password_encrypted2 = "";

		System.out.println("pass from gui: " + tempPass);

		try {

			// initial password after being hashed using SHA-1
			// represented as byte[]
			byte[] hashedPassword = new PasswordEncryption()
					.getEncryptedPassword(tempPass,
							new PasswordEncryption().getSalt());

			// hashed password stored as string
			// this version of the password will be stored in the db
			password_encrypted2 = DatatypeConverter
					.printHexBinary(hashedPassword);
			ceDTO.setPassword(password_encrypted2);
		} catch (NoSuchAlgorithmException | InvalidKeySpecException
				| UnsupportedEncodingException e) {
			e.printStackTrace();
		}

		User auxCE = conv.fromDTO(ceDTO);
		List<Role> roles = conv.convertRolesFromDTO(ceDTO);
		System.out.println("Roles in list: ");
		
		
		// set user for roles
		for(int i=0; i<roles.size(); i++) {
			List<User> userListForRole = new ArrayList<>();
			User myUser = auxCE;
			userListForRole.add(myUser);
			System.out.println(roles.get(i).toString());
		}
		
		// set roles for user
		auxCE.setRoles(roles);
		
		entityManager.persist(auxCE);

		// send email with instructions to activate account
		sendInstructionsEmail("newAccount", ceDTO.getWorkEmail(),
				ceDTO.getUsername(), password_encrypted2);
	}

	@Override
	public ConfidentialEmployeeDTO findById(int id) {
//		System.out.println("in dao, findById, id: " + id);
		ConfidentialEmployee ce = entityManager.find(
				ConfidentialEmployee.class, id);
		
		System.out.println("Conf employee dao, dinfById, ce: " + ce);
		
		if(ce != null) {
			ConfidentialEmployeeDTO cedto = conv.fromEntity(ce);
			
			List<Integer> rolesID = conv.convertRolesFromEntity(ce);
			cedto.setRolesIdList(rolesID);

			return cedto;
		} else {
			return null;
		}
		
		
	}

	@Override
	public List<ConfidentialEmployeeDTO> getAll() {
		List<ConfidentialEmployee> ceList = entityManager.createQuery(
				"Select ce from ConfidentialEmployee ce",
				ConfidentialEmployee.class).getResultList();

		List<ConfidentialEmployeeDTO> confEmployeesDTO = new ArrayList<ConfidentialEmployeeDTO>();

		for (ConfidentialEmployee ce : ceList) {
			ConfidentialEmployeeDTO uDTO = new ConfidentialEmployeeDTO();
			uDTO = conv.fromEntity(ce);
			confEmployeesDTO.add(uDTO);

		}

		return confEmployeesDTO;
	}

	@Override
	public void edit(ConfidentialEmployeeDTO ceDTO) {
		
		User auxCE = conv.fromDTO(ceDTO);
		List<Role> roles = conv.convertRolesFromDTO(ceDTO);
		System.out.println("Roles in list: ");
		
		// set user for roles
		for(int i=0; i<6; i++) {
			List<User> userListForRole = new ArrayList<>();
			User myUser = null;
			userListForRole.add(myUser);
//			System.out.println(roles.get(i).toString());
		}

		// set roles for user
		auxCE.setRoles(null);
//		auxCE.addRoles(r);
		
		entityManager.merge(auxCE);
		entityManager.flush();
		
		for(int i=0; i<roles.size(); i++) {
			List<User> userListForRole = new ArrayList<>();
			User myUser = auxCE;
			userListForRole.add(myUser);
			System.out.println(roles.get(i).toString());
		}
		auxCE.setRoles(roles);
		entityManager.merge(auxCE);
		entityManager.flush();
		
		
	}

	@Override
	public void remove(ConfidentialEmployeeDTO ceDTO) {
		ConfidentialEmployee confEmp = entityManager.find(
				ConfidentialEmployee.class, conv.fromDTO(ceDTO).getId());
		entityManager.remove(confEmp);
	}

	public void sendInstructionsEmail(String emailPurpose,
			String receiverEmail, String receiverUsername, String encryptPass) {
		MailSender ms = new MailSender();

		String emailSender = "no-reply@msg-systems.com";
		String emailSubject = "";
		String emailContent = "";

		// property file that contains ip address of server
		// on which project is run
		// at the moment - localhost
		Properties ipConfigFile = new Properties();
		// property file is stored in META-INF folder
		InputStream myIS = getClass().getClassLoader().getResourceAsStream(
				"META-INF/ipconfigs.properties");

		try {
			// open property file
			ipConfigFile.load(myIS);
		} catch (IOException e) {
			e.printStackTrace();
		}

		// get value of "ip" property
		String ipAddress = ipConfigFile.getProperty("ip");
		String firstAccessLink = ipAddress
				+ "LastProjectWeb/faces/changePassword.xhtml" + "?logUsername="
				+ receiverUsername + "&logPassword=" + encryptPass;

		switch (emailPurpose) {

		case "newAccount":
			emailSubject = "Your account was created";
			emailContent = "Click the link provided below and follow the instructions"
					+ " to activate your account.\n\n" + firstAccessLink;
			break;
		}

		ms.sendMail(emailSender, receiverEmail, emailSubject, emailContent);
	}

	@Override
	public List<ConfidentialEmployeeDTO> findByCriteria(String name,
			String position, String employmentType, Date startEmploymentDate,
			Date endEmploymentDate, Date startLastMedCheckDate,
			Date endLastMedCheckDate, boolean enabledAccount, int roleId,
			int departmentId, String germanContactPers, String careerLevel,
			float startSalary, float endSalary) {

		List<ConfidentialEmployee> results = new ArrayList<ConfidentialEmployee>();

		String selectPart = "SELECT DISTINCT ce FROM ConfidentialEmployee ce";
		StringBuilder wherePart = new StringBuilder();
		wherePart.append(" WHERE ");

		//		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

		boolean previous = false;

		if (!name.isEmpty()) {
			wherePart.append("("
					+ "(ce.firstname LIKE '%" + name + "%') "
					+ "or (ce.lastname LIKE '%" + name + "%') "
					+ "or (concat(ce.firstname, ' ', ce.lastname) = '" + name + "') "
					+ "or (concat(ce.lastname, ' ', ce.firstname) = '" + name + "')"
					+ ")");
			previous = true;
		}

		if (!position.isEmpty()) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.position = '" + position + "')");
			previous = true;
		}

		if (!employmentType.isEmpty()) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.employmentType = '" + employmentType + "')");
			previous = true;
		}

		if ((startEmploymentDate != null) && (endEmploymentDate != null) && 
				(startEmploymentDate.compareTo(endEmploymentDate) < 0)) {
			// between start and end
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.employmentDate BETWEEN '"
					+ new java.sql.Date(startEmploymentDate.getTime()) + "' AND '" 
					+ new java.sql.Date(endEmploymentDate.getTime()) + "')");
			previous = true;
		} else if (startEmploymentDate != null && (endEmploymentDate == null)) {
			// from start onwards
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.employmentDate > '" + new java.sql.Date(startEmploymentDate.getTime()) + "')");
			previous = true;
		}

		if ((startLastMedCheckDate != null) && (endLastMedCheckDate != null) && 
				(startLastMedCheckDate.compareTo(endLastMedCheckDate) < 0)) {
			// between start and end
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.medCheckUpDate BETWEEN '"
					+ new java.sql.Date(startLastMedCheckDate.getTime()) + "' AND '" 
					+ new java.sql.Date(endLastMedCheckDate.getTime()) + "')");
			previous = true;
		} else if (startLastMedCheckDate != null && (endLastMedCheckDate == null)) {
			// from start onwards
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.medCheckUpDate > '" + new java.sql.Date(startLastMedCheckDate.getTime()) + "')");
			previous = true;
		}

		// department
		if (departmentId != 0) {
			if (previous) {
				wherePart.append(" AND ");
			}

			wherePart.append("(ce.department.id = " + departmentId + ")");
			previous = true;
		}

		if (enabledAccount == true) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.enabled = " + 1 + ")");
			previous = true;
		} else {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.enabled = " + 0 + ")");
			previous = true;
		}

		if (!germanContactPers.isEmpty()) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.germanContactPerson = '" + germanContactPers
					+ "')");
			previous = true;
		}

		if (!careerLevel.isEmpty()) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.careerLevel = '" + careerLevel + "')");
			previous = true;
		}

		if ((startSalary == endSalary) && startSalary != 0) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.salary = " + startSalary + ")");
			previous = true;
		} else if (startSalary != 0 && endSalary != 0) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.salary BETWEEN " + startSalary + " AND "
					+ endSalary + ")");
			previous = true;
		} else if (startSalary != 0 && endSalary == 0) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.salary > " + startSalary + ")");
			previous = true;
		} else if (startSalary == 0 && endSalary != 0) {
			if (previous) {
				wherePart.append(" AND ");
			}
			wherePart.append("(ce.salary < " + endSalary + ")");
			previous = true;
		}

		String fullQuery = selectPart + wherePart.toString();
		System.out.println("Search- executing following query: ");
		System.out.println(fullQuery);

		results = entityManager.createQuery(fullQuery,
				ConfidentialEmployee.class).getResultList();

		List<ConfidentialEmployeeDTO> resultsDTO = new ArrayList<ConfidentialEmployeeDTO>();

		for (ConfidentialEmployee ce : results) {
			resultsDTO.add(conv.fromEntity(ce));
		}
		
		return resultsDTO;

	}
	
	@Override
	public boolean checkIfDeparmentHasManager(int departmentId) {
		// employee - isDepartmentManager
		// employee - deparmentID
		Department department = entityManager.find(Department.class, departmentId);
		
		List<Employee> listOfDepartmentManagers = entityManager
				.createQuery("SELECT ce FROM Employee ce JOIN ce.department d "
						+ "WHERE ce.isDepartmentManager = '1' "
						+ "AND d.id = :department" , Employee.class)
						.setParameter("department", departmentId)
						.getResultList();
		System.out.println("checkIfDeparmentHasManager id dep is" + departmentId);
		System.out.println("checkIfDeparmentHasManager " + listOfDepartmentManagers.size());
		
		if(listOfDepartmentManagers.size() > 0) {
			// department has manager
			return true;
		} else
			// department doesn't have manager
			return false;		
	}
	
	@Override
	public ConfidentialEmployeeDTO findByWorkemail(String workemail) {
		List<ConfidentialEmployee> ceList = new ArrayList<>();
		
		ceList = entityManager
				.createQuery("SELECT ce FROM ConfidentialEmployee ce "
						+ "WHERE ce.workEmail = :workemail", ConfidentialEmployee.class)
						.setParameter("workemail", workemail)
						.getResultList();
		
		if(ceList.size() != 0) {
			ConfidentialEmployeeDTO cedto = conv.fromEntity(ceList.get(0));			
			List<Integer> rolesID = conv.convertRolesFromEntity(ceList.get(0));
			cedto.setRolesIdList(rolesID);
			
			return cedto;
		} else {
			return null;
		}		
	}

}
